home *** CD-ROM | disk | FTP | other *** search
/ C/C++ 3D Game Tools / C-C++ 3D Game Tools.iso / tools / floormap.txt < prev    next >
Text File  |  1997-02-25  |  11KB  |  443 lines

  1. FLOOR MAPPING INFO FILE THING:
  2. ===============================
  3. S. Christian Flowers June 1995
  4. Email: LYRIXX@aol.com
  5.  
  6. Freely Distributed: I was feeling in a giving frame of mind
  7.  
  8. ===========================================================
  9.  
  10. Ok, as per request here is info for floor mapping
  11. I will stick to C/C++, no ASM will be explained.
  12. To help as many people as I can, I'll try and keep it ANSI
  13. I program in 32-Bit DOS. But the Method, outside of optimizing,
  14. can be in 16-Bit too.
  15.  
  16. Quick Overview
  17. ===============
  18. 1. We assume 90 viewport. Speed is the reason for this
  19.  
  20. 2. The basic equation used for finding the falloff rate to the
  21.    horizon is:
  22.  
  23.    zdistance = (distance_to_screen * player_height) / screen_y_position;
  24.  
  25. 3. Distance to the screen is up to you. 160,128,256..what ever you choose.
  26.    I suggest 128 or 256 so the fall off can be done a litte faster if
  27.    computed at runtime. 
  28.  
  29.    for example: if you choose distance_to_screen to be 128
  30.    
  31.    zdistance = (player_height<<7) / screen_y_position;
  32.  
  33. 4. The tile size I use is 256X256. This can easily be reduced to 64X64.
  34.    Why 256X256? It gives a smoother result at low floor height and
  35.    the graphic looks cleaner.
  36.  
  37.    Most programmers may be used to ANDing the value by 63 at get
  38.    the tile value. I never liked the results useing that method.
  39.    I choose 256 X 256 because you can do this:
  40.  
  41.    int worldcoord = 204837; 
  42.    unsigned char tileval=worldcoord;
  43.  
  44.    C will autowrap tileval with an 0-255 for you without any need 
  45.    of checking the range of worldcoord.
  46.  
  47.    Then tileval/4 or tileval>>2  will give you an 0-63 value.
  48.  
  49.    I will admit worldcoor&63 is faster but it just looks crummy 
  50.    at a low floor height. your call can do what you want.
  51.  
  52.  5. Screen assumed to be 320X200
  53.  
  54.  
  55. Ok, The basic Algorithm:
  56. ========================
  57.  
  58.    int count=32000; //counts into the screen buffer the current pixel 
  59.                     //to be drawn. set to start at horizon i.e. mid screen
  60.                     //100*320
  61.  
  62.   for(i=0;i<100; i++,count++){ //count from horizon to bottom of screen
  63.       
  64.       compute falloff or z distance for this line
  65.       
  66.       get left edge = z_dist   + Player xy
  67.       get right edge = -z_dist + Player xy
  68.       
  69.       rotate left and right edge points
  70.       
  71.       get xspan = distance between Leftx and Rightx values
  72.       get yspan = distance between Lefty and Righty values
  73.       
  74.       xscale=xspan/screenwidth
  75.       yscale=yspan/screenwidth
  76.  
  77.       sx,sy begin at left edge
  78.  
  79.    for(j=0; j<screenwidth; j++){
  80.        
  81.        tilex=sx;  //force an 0-255 value
  82.        tiley=sy;
  83.        
  84.        choose 1 of these and draw pixel at count:
  85.        ==========================================
  86.        1. buffer[count]=tile[(tiley*256)+tilex];    //256X256
  87.        2. buffer[count]=tile[(tiley<<8)+tilex];     //faster 256X256
  88.        3. buffer[count]=tile[((tiley>>2)<<6)+(tilex>>2)]; //faster 64X64
  89.  
  90.        sx+=xscale;  //step to next
  91.        sy+=yscale;
  92.  
  93.      }
  94.  
  95.    }
  96.   done
  97.  
  98. ==================================
  99. A INDEPTH OVERVIEW OF FLOORMAPPING
  100. ==================================
  101.  
  102. I program in 32-DOS so to avoid bugs in your code here are the data  
  103. sizes:
  104.      char = 1 byte
  105.      short= 2 bytes
  106.      int  = 4 bytes
  107.  
  108. Now the player:
  109.  
  110.  int pa;        //player angle
  111.  int ph=128;    //player height
  112.  int px=2048;   //player start x
  113.  int py=2048;   //player y
  114.  int pspeed=15; //player speed of movement
  115.  int pxv;       //player x velocity
  116.  int pyv;       //player y velocity
  117.  
  118. Player movement is calculated as follows:
  119.  
  120.    pxv=0-pspeed*SIN(pa); //compute x & y velocities
  121.    pyv=0+pspeed*COS(pa);
  122.    px+=pxv;              //move the player
  123.    py+=pyv;
  124.  
  125. Why the extra 0 in there? This is why:
  126. if you look at the world from a topdown position
  127. it looks like this:
  128.                     -Y
  129.                      |   
  130.                -X----0----+X        player at 0
  131.                      |
  132.                     +Y
  133.  
  134. we want the player to default faceing SOUTH i.e. +Y direction
  135. so the view cone defaults like this:
  136.                    
  137.                    -Y
  138.                     |
  139.                    EYE player at 0
  140.                    /|\
  141.                  /  |  \
  142.                /    |    \
  143.              /      |      \
  144.             -----------------   SCREEN topdown
  145.      Right -X     SOUTH     +X  Left
  146.                    +Y
  147.  
  148. This also makes ScreenLeft +X and ScreenRight -X.
  149. All of this has its advantages, though it may seem wierd right now.
  150. One advantage is we always compute the floors falloff distance in
  151. the direction of +Y so we need to default the player in that direction.
  152.  
  153. FALLOFF
  154. =======
  155. We look at the world topdown 2D the player faceing +Y as explained above.
  156. There are 100 horizontal screen lines from the horizon to the bottom
  157. of the screen. So the falloff distance refers to +Y going away from 
  158. the player. Line 1 is the horizon and line 100 is the bottom of the screen
  159.    
  160.  SIDE VIEW of calculating falloff
  161.  ================================         
  162.           SCREEN 
  163.             |
  164.             |
  165.             |
  166.             |                        
  167.  EYE -------|1-----------------------------> Faceing SOUTH
  168.   | \       |                             
  169.   |   \     |
  170.   |     \   |
  171.   |       \ |
  172.   |         .100  current ScreenYpos (1-100)
  173.   |           \  
  174.   |             \
  175.   Height----------.-------------------------
  176.                     Falloff +Y
  177.  
  178.   Falloff=(EyetoScreen*Height)/ScreenYpos;
  179.   
  180.   Generate a lookup for Height
  181.   ============================
  182.   float falloffdistance[100];  //floats are converted to fixed point later
  183.   float ScreenYpos=1.000;
  184.   float EyetoScreen=128.000;
  185.   float Height=playerheight;
  186.   
  187.   for(i=0;i<100;i++,ScreenYpos+=1.000){
  188.     
  189.     falloffdistance[i]=(EyetoScreen*Height)/ScreenYpos;
  190.   
  191.   }
  192.  
  193.   We begin ScreenYpos at 1 rather than 0 to avoid a divide by 0
  194.   error that would result.
  195.  
  196. XWIDTH
  197. ======
  198. +Y is the falloff at each horizontal line on Screen.
  199. Left X to Right X is the X width at each +Y distance.
  200. So, if the screen is 320 pixels wide, we just divide the X width by 320
  201. to cut the X width into 320 equal parts then loop through them and
  202. draw 320 pixels to the screen.
  203.  
  204. This is where the 90 degree viewport saves some effort. 
  205. If +Y equals 25600 then Left X is 25600 and Right x is -25600,
  206. remember the players faces south so Right is -X.
  207.  
  208.                          EYE    Faceing South
  209.                          /|\
  210.                        /  |  \
  211.                      /    |    \
  212.                    /      |      \
  213.                  /        |        \
  214.                /          |          \
  215.   Screen Right. ----------|------------.Screen Left
  216.            /              |             \
  217.          /                |               \
  218.  Rx,Ry /.                 |                .\Lx,Ly
  219.                        Fall off
  220.  -X                      +Y                   +X
  221.  
  222. With these values we create a line:
  223.  
  224.   Lx=Y;  Ly=Y; //the left edge
  225.   Rx=-Y; Ry=Y; //the right edge
  226.  
  227. Now if we wanted to map this horizontal line to the screen: 
  228.  
  229.    float xstep=-((Lx-Rx)/320);
  230.    float lx=Lx+playerx;
  231.    unsigned char x;
  232.    unsigned char y=Ly+playery; //or Ry doesn't matter here, but it will later
  233.  
  234.    for(i=0;i<320;i++){  //map 320 pixels at +Y
  235.    
  236.           x=lx;  //force 0-255 vaule
  237.  
  238.           screen[i]=tile[(y*256)+x]; //draw it
  239.  
  240.           lx+=xstep; //step to next
  241.    }
  242.  
  243. In doing the above at each of the 100 ScreenY positions
  244. You will map a non-rotated floor. But...that sucks.
  245.  
  246. Rotations
  247. =========
  248.  I use a 640 degree system. Everything is programmed in fixed point
  249.  and all floats can be removed. But for this file I will explain
  250.  useing floats. You will have to write your code in fixed point if 
  251.  you want realtime results.
  252.  
  253.  So first off we need Sine & Cosine Tables
  254.  
  255.  float SIN[640];  //global arrays
  256.  float COS[640];
  257.  
  258. // 
  259. //Makes Sin & Cos Tables num is number of degrees
  260. //
  261. void maketrigtables(int num){
  262.      int i;
  263.      float radians=0;
  264.  
  265.      for(i=0;i<num;i++){
  266.         COS[i]=cos(radians);
  267.         SIN[i]=sin(radians);
  268.         radians=6.28/num;
  269.      }
  270.  
  271.   return;
  272.  }
  273.  
  274. For those who don't know:
  275. =========================
  276. Rotating a 2d point is done as follows:
  277.  
  278. int x=10; int y=10; //original coords
  279. int nx,ny;          //the new coords
  280. int a=20;           //the angle of rotation 0-639
  281.  
  282.    nx=(x*COS[a])-(y*SIN[a]);
  283.    ny=(x*SIN[a])+(y*COS[a]);
  284.  
  285. So,in knowing this we can all move to the final stages of codeing this thing
  286.  
  287. HERE GOES...THE FLOOR MAPPER
  288. =============================
  289. //
  290. //  a   is the angle of rotation
  291. //  fh  is the floor's height
  292. //
  293. //  all in float where needed
  294. //
  295. //  I'll write for a 64X64 tile
  296. //  buffer[] is assume 64k i.e. 320X320
  297. //
  298. void slowmapfloor(int a,int fh){
  299.  
  300.    int count=32000;     //set pixel counter at horizon
  301.    int i,j;             //loop counters
  302.    float ypos=1.00;     //current ypos
  303.    float Lx,Ly;         //Left edge end point
  304.    float Rx,Ry;         //Right edge end point
  305.    float fdist;         //fall off distance
  306.    float xstep;         //to walk x values
  307.    float ystep;         //to walk y values
  308.    float x,y;           //current world position
  309.    float dts=128;       //distance to screen from eye
  310.    float fheight=fh;    //float height
  311.    unsigned char tx,ty; //tile x and y 
  312.    float fdsin,fdcos;   //Sin and Cos values at fdist to speed up routine
  313.  
  314.    for(i=0;i<100;i++,ypos+=1.00){   //loop screen y : 100 lines
  315.  
  316.      fdist=(fheight*dts)/ypos;  //compute falloff    
  317.       
  318.      //Compute and Rotate Left and Right endpoints
  319.      fdsin=fdist*SIN[a];  //speed up the rotations a little
  320.      fdcos=fdcos*COS[a];  //with this
  321.  
  322.      Lx=fdcos-fdsin;    //rotate Left edge
  323.      Ly=fdsin+fdcos;
  324.  
  325.      Rx=(-fdcos)-fdsin; //rotate Right Edge
  326.      Ry=(-fdsin)+fdcos;
  327.  
  328.      //Compute xstep and ystep 
  329.      if(Lx>Rx){ xstep=(Lx-Rx)/320; xstep=-xstep}  //xstep
  330.       else{ xstep=(Rx-Lx)/320;}
  331.      
  332.      if(Ly>Ry){ ystep=(Ly-Ry)/320; ystep=-ystep}  //ystep
  333.       else{ ystep=(Ry-Ly)/320;}
  334.  
  335.      x=Lx+px; y=Ly+py; //start at left edge
  336.  
  337.       for(j=0;j<320;j++,count++){ // loop screen x: 320 pixels
  338.  
  339.         tx=x; ty=y; //force 0-255 results
  340.       
  341.         buffer[count]=tile[((ty>>2)<<6)+(tx>>2)]; //draw 1 pixel
  342.  
  343.         x+=xstep; //step to the next x & y position
  344.         y+=ystep;
  345.       
  346.       }//end j
  347.  
  348.    }//end i
  349.  
  350.  return;
  351. }
  352.  
  353.  
  354.  
  355. Tadah...That's it. I hope it helps 
  356.  
  357. BUT WAIT!
  358. =========
  359. As written it is SLOW as the government comeing forth about Aliens
  360. Optimized and it blazes. So convert any and all floats to fixed point
  361. would be a start. That will increase speed but not as fast as it could
  362. be.
  363.  
  364. Hints on optimizing
  365. ====================
  366.  
  367.   pointers:  the buffer[] portion can be written better
  368.  
  369.   As written is:
  370.   --------------
  371.   count=32000;
  372.  
  373.   for(i=0;i<100;i++){
  374.  
  375.    for(j=0;j<320;j++,count++){
  376.  
  377.     buffer[count]=pixel;
  378.  
  379.    }
  380.  
  381.   }
  382.  
  383.   Faster:
  384.   -------
  385.   unsigned char *buf=buffer+32000;
  386.  
  387.   for(i=0;i<100;i++){
  388.  
  389.    for(j=0;j<320;j++,buf++){
  390.  
  391.     *(buf)=pixel;
  392.  
  393.    }
  394.  
  395.   }
  396.  
  397.  That will kill 32000 underlying additions C does when offsetting
  398.  from the pointer when buffer[count] was used.
  399.  
  400.  There are even faster ways in 32-Bit C++ useing unions
  401.  to allow drawing 4 pixels at once. And I don't mean MODE X.
  402.  But I'll keep those to myself. Hey, You can't have it all for free.
  403.  
  404.  LAST WORDS:
  405.  ============
  406.  In case you didn't notice, You just go 100 -> 1 in the outerloop
  407.  to map a ceiling.
  408.  
  409.  Any questions Email me LYRIXX@aol.com
  410.  
  411.  ** END OF FILE **
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.